package org.kitten.core.util;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Collections;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.apache.commons.lang.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * @author sb.yin(uniquejava@gmail.com)
 * @version 1.0
 * @since 2010-8-18
 */
public class ClassUtil {
    private static final Log logger = LogFactory.getLog(ClassUtil.class);
	/**
	 * 动态加载jar包
	 * 
	 * @param jar
	 * @throws Exception
	 */
	public static void loadJar(String jar) throws Exception {
		URL urls[] = new URL[] { new File(jar).toURL() };

		// 获取类装载器，然后用反射方式调用类加载器的addURL方法，把新的jar路径添加进去
		URLClassLoader urlLoader = (URLClassLoader) getDefaultClassLoader();
		Method method = URLClassLoader.class.getDeclaredMethod("addURL",
				new Class[] { URL.class });
		method.setAccessible(true);
		method.invoke(urlLoader, urls);
	}

	/**
	 * 取得指定jar包中实现了某指定接口的所有类的名字
	 * 
	 * @param jar
	 * @param interfaceName
	 * @return
	 * @throws Exception
	 */
	public static String[] getImplementationOfInteraceFromJar(File jar,
			String interfaceName) throws Exception {

		StringBuffer sb = new StringBuffer();
		String jarName = jar.getAbsolutePath();
		// 首先将jar包加载到类路径
		loadJar(jarName);
		// 遍历找到的所有类名，判断它是否实现了相应的接口.
		List<JarEntry> list = Collections.list(new JarFile(jarName).entries());
		for (JarEntry e : list) {
			String n = e.getName();
			if (n.endsWith(".class")) {
				n = n.substring(0, n.length() - 6);
				// 类的名字
				String clazzName = n.replace('/', '.');
				// 尝试加载类
				Class clazz = null;
				try {
					clazz = Class.forName(clazzName);
				} catch (NoClassDefFoundError ex) {
					continue;
				} catch (ClassNotFoundException ex) {
					continue;
				}

				// 取类的所有接口
				Class[] interfaces = clazz.getInterfaces();
				for (int j = 0; j < interfaces.length; j++) {
					if (interfaces[j].getName().equals(interfaceName)) {
						sb.append(clazzName + ",");
						break;
					}
				}
				// if (find) {// 找到一个类后就立即退出
				// break;
				// }
			}
		}
		if (sb.length() > 0) {
			sb.setLength(sb.length() - 1);
		}
		return sb.toString().split(",");
	}

	public static void main(String[] args) throws Exception {
		// （1）调用未打成jar包的类
		/*URL url = new File("d:/").toURL();
		URLClassLoader classLoader = new URLClassLoader(new URL[] { url });
		Class c = classLoader.loadClass("test.User");
		Method[] mthods = c.getDeclaredMethods();
		for (int i = 0; i < mthods.length; i++) {
			Method m = mthods[i];
			if (m.getName().equals("sayHello")) {
				m.invoke(c.newInstance(), "ysb");
			}
		}

		// （2）调用打成jar包的类
		// 将jar包加载到类路径
		loadJar("d:/test.jar");
		// 测试加载的类
		Class user = Class.forName("test.User");
		Method m = user.getDeclaredMethod("sayHello",
				new Class[] { String.class });
		m.invoke(user.newInstance(), "ysb");*/

		// (3)遍历jar中的类，找出实现了java.sql.Driver接口的类
		String jarName = "D:/SmartLibrary/all/ojdbc14_g.jar";
//		String[] finds = getImplementationOfInteraceFromJar(new File(jarName),
//				"java.sql.Driver");
//		for (int i = 0; i < finds.length; i++) {
//			System.out.println(finds[i]);
//		}
		loadJar(jarName);
		Class.forName("oracle.jdbc.driver.OracleDriver");
		Connection conn = null;
		try {
			conn = DriverManager.getConnection("jdbc:oracle:thin:@128.96.96.80:1521:admasdb","orasuser","orasuser");
			if (conn != null) {
				System.out.println("连接成功.");
			} else {
				System.out.println("连接失败,conn返回null.");
			}
		} finally {
			DbUtil.close(null, null, conn);
		}
	}

	/**
	 * Return the default ClassLoader to use: typically the thread context
	 * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
	 * class will be used as fallback.
	 * <p>
	 * Call this method if you intend to use the thread context ClassLoader in a
	 * scenario where you absolutely need a non-null ClassLoader reference: for
	 * example, for class path resource loading (but not necessarily for
	 * <code>Class.forName</code>, which accepts a <code>null</code>
	 * ClassLoader reference as well).
	 * 
	 * @return the default ClassLoader (never <code>null</code>)
	 * @see java.lang.Thread#getContextClassLoader()
	 */
	public static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			cl = Thread.currentThread().getContextClassLoader();
		} catch (Throwable ex) {
			logger.error("Cannot access thread context ClassLoader - falling back to system class loader",
							ex);
		}
		if (cl == null) {
			// No thread context class loader -> use class loader of this class.
			cl = ClassUtils.class.getClassLoader();
		}
		return cl;
	}
}
